//   -------------------- iSharePoint -------------------- //
//  
//   Company:	IT Complex, LLC
//   Project:	Smart.Common
//   File name:	RequestStore.cs
//   Developer:	Igor Solomatov
//   Created:	25.08.2012
//  
//   -------------------- iSharePoint -------------------- //

using System;
using System.Collections;
using System.Web;

namespace Smart
{
	/// <summary>
	/// Request store
	/// </summary>
	public static class RequestStore
	{
		[ThreadStatic]
		public static Hashtable ThreadStore;

		/// <summary>
		/// Returns request store
		/// </summary>
		public static Hashtable GetStore()
		{
			var res = ThreadStore;

			if (res != null)
				return res;

			var ctx = HttpContext.Current;

			return
				ctx != null
					? (Hashtable)ctx.Items
					: ThreadStore = new Hashtable();
		}

		/// <summary>
		/// Returns request store value by <paramref name="key"/>
		/// </summary>
		public static TValueType Get<TValueType>(object key)
		{
			return (TValueType)GetStore()[key];
		}

		/// <summary>
		/// Returns request store value by <paramref name="key"/>, if not exists or null returns <paramref name="defaultValue"/>
		/// </summary>
		public static TValueType Get<TValueType>(object key, TValueType defaultValue)
		{
			return (TValueType)(GetStore()[key] ?? defaultValue);
		}

		/// <summary>
		/// Returns request store value by <paramref name="key"/>, if not exists or null calls <paramref name="loader"/> to load and Set value
		/// </summary>
		public static TValueType Get<TValueType>(object key, Func<object, TValueType> loader)
		{
			var s = GetStore();

			var v = s[key];

			if (v == null)
				s[key] = v = loader(key);

			return (TValueType)v;
		}

		/// <summary>
		/// Set request store <paramref name="value"/> by <paramref name="key"/>
		/// </summary>
		public static void Set<TValueType>(object key, TValueType value)
		{
			GetStore()[key] = value;
		}
	}

	/// <summary>
	/// Cached RequestStore As it caches RequestStore, should not be used across request.
	/// </summary>
	[Serializable]
	public class RequestStore<TValueType>
	{
		[NonSerialized]
		private Hashtable _store;

		public Hashtable Store
		{
			get { return _store ?? (_store = RequestStore.GetStore()); }
		}

		/// <summary>
		/// Gets or Sets <paramref name="value"/> by <paramref name="key"/>
		/// </summary>
		public TValueType this[object key]
		{
			get { return (TValueType)Store[key]; }
			set { Store[key] = value; }
		}

		/// <summary>
		/// Gets value by <paramref name="key"/>, if it not exists or null, returns <paramref name="defaultValue"/>
		/// </summary>
		public TValueType this[object key, TValueType defaultValue]
		{
			get { return Store.SafeGet(key, defaultValue); }
		}

		/// <summary>
		/// Gets value by <paramref name="key"/>, if not exists or null, calls <paramref name="loader"/> to load and set value
		/// </summary>
		public TValueType this[object key, Func<object, TValueType> loader]
		{
			get { return Store.SafeGetLoad(key, loader); }
		}
	}
}